import wx
import wx.glcanvas
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
import sys,math,time,gameflags,hub


class reactor:
    def __init__(self,world):
        self.core = None
        self.world = world
        self.backend = wx.PySimpleApp()
        self.mainframe = wx.Frame(None,-1,'3D Render Engine',wx.DefaultPosition,wx.Size(400,400))
        self.widget = myGLCanvas(self.backend,self.mainframe,self.world)
        self.factory = factory(self.mainframe)
        
    def run(self):
        self.mainframe.Show()
        self.mainframe.SetCursor(wx.StockCursor(wx.CURSOR_BLANK))
        self.backend.MainLoop()

class factory:
    def __init__(self,mainframe):
        self.mainframe = mainframe
    def setSize(self,size):
        self.mainframe.SetSize(size)
    def setTitle(self,text):
        self.mainframe.SetTitle(text)

class event:
    def __init__(self):
        self.keys = None
        self.mouse = None

class myGLCanvas(wx.glcanvas.GLCanvas):
    def __init__(self, app, parent, world):
        wx.glcanvas.GLCanvas.__init__(self, parent,-1)

        self.Bind(wx.EVT_PAINT,self.OnPaint)
        self.Bind(wx.EVT_IDLE, self.OnPaint)
        self.Bind(wx.EVT_MOUSE_EVENTS, self.MouseMovement)
        self.Bind(wx.EVT_KEY_DOWN,self.KeysDown)
        
        self.m_leftdown = False
        
        self.t0 = time.time()
        self.frames = 0
        self.app = app
        self.parent = parent
        self.world = world
        self.key = ""
        self.InitGL()
        self.Show()
    
    def framerate(self):
        t = time.time()
        self.frames += 1
        if t - self.t0 >= 1.0:
            seconds = t - self.t0
            fps = self.frames/seconds
            print "%.0f frames in %3.1f seconds = %6.3f FPS" % (self.frames,seconds,fps)
            self.t0 = t
            self.frames = 0
            
    def mouseto3d(self,x,y):
        viewport   = glGetIntegerv( GL_VIEWPORT )
        modelview  = glGetDoublev(  GL_MODELVIEW_MATRIX )
        projection = glGetDoublev(  GL_PROJECTION_MATRIX )
    
        winX = float( x )
        winY = float( viewport[3] ) - float( y )
        winZ = glReadPixels(x,viewport[3]-y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT)
        
        return gluUnProject( winX, winY, winZ, modelview, projection, viewport)
      
    def MouseMovement(self,event):
        #print dir(event)
        (x,y) = event.GetPosition()
        """
        ## Test Object Selection
        self.world.render(mode=gameflags.RENDER_PICKY)
        
        viewport = glGetIntegerv(GL_VIEWPORT)
        pixel = glReadPixels(x,viewport[3]-y,1,1,GL_RGB,GL_BYTE)
        (r,g,b) = pixel[0][0]
        for mesh in self.world.meshes:
            (rm,gm,bm) = mesh.pickyCol
            rm = int(math.floor(rm*127/1))
            gm = int(math.floor(gm*127/1))
            bm = int(math.floor(bm*127/1))
            #print (r,g,b), (rm,gm,bm)
            if (r,g,b) == (rm,gm,bm):
                mesh.selected = True
            else:
                mesh.selected = False
        """
        self.mPos = (x,y)
        if event.LeftDown():
            self.m_leftdown = True
            
        
        
    def KeysDown(self,event):
        try:
            unicode = unichr(event.GetKeyCode())
            if unicode == u'\x08': ## Backspace
                self.key = self.key[:-1]
            elif unicode == u'\u0132': ## Shift
                pass
            elif unicode == u' ': ## Space
                self.key += " ";
            elif unicode == u'\r': ## Enter/Return
                pass
            else:
                if event.ShiftDown():
                    self.key += unichr(event.GetKeyCode())
                else:
                    self.key += unichr(event.GetKeyCode()).lower()
        except UnicodeEncodeError:
            self.key += "" #event.GetKeyCode()
        
        if event.GetKeyCode() == 27:
            self.app.ExitMainLoop()
            self.app.Destroy()
        self.world.processEvent(event)
        
    def OnPaint(self,event):
        self.SetCurrent()
        self.framerate()
        self.OnDraw()

    def OnDraw(self):
        (w,h) = self.GetSize()
        glViewport(0, 0, w, h)
        
        glClearColor(0.0, 0.0, 1.0, 1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glClearDepth(1.0)

        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(self.world.camera.perspective, w/float(h or 1), self.world.camera.near, self.world.camera.far)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        self.world.camera.render()
        
        
        ## Render Terrain
        
        ## Render World
        self.world.render()
        
        ## Events
        if self.m_leftdown:
            ( x, y ) = self.mPos
            y = h - y
            print self.mouseto3d(x,y)
            self.m_leftdown = False
        
            
        ## Convert to ortho to render hub & mouse
        glViewport(0,0,w,h);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0,w,0,h,-100,100);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity()
        gluLookAt(  0, 0, 50,
                    0, 0,  0,
                    0, 1,  0);
        
        ## Render Hub
        if self.key != None:
            self.font.render(self.key)
        self.panel.render()
        
        ## Render Mouse
        if hasattr(self,'mPos'):
            ( x, y ) = self.mPos
            y = h - y
            self.mouse.render('pointer',[x,y])
        
        
        self.SwapBuffers()
        errors = glGetError()
        while errors:
            print "OpenGL Error: %s"%errors
            errors = glGetError()
        
    
    def InitGL(self):
        (w,h) = self.GetSize()
        #glutInit(sys.argv)
        glViewport(0, 0, w, h)
        glClearColor(0.0, 0.0, 1.0, 1.0)
        glClearDepth(1.0)

        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(40.0, 1.0, 0.25, 200.0)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        self.world.camera.render()
        ## Init font
        self.font = hub.font()
        ## Init mouse
        self.mouse = hub.mouse()
        ## Init GUI
        self.panel = hub.Panel()
    
